feat(reconcile): add a Preference kind#1762
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
📝 WalkthroughSummary by CodeRabbit
WalkthroughAdds platform preferences as a declarative reconcile and export kind, including validation, default-reset semantics, dry-run and apply behavior, non-default export filtering, CLI registration, documentation, and test coverage. ChangesPreference reconciliation
Estimated code review effort: 3 (Moderate) | ~25 minutes Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 2✅ Passed checks (2 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Coverage Report for CI Build 29488954811Coverage increased (+0.1%) to 45.987%Details
Uncovered Changes
Coverage Regressions1 previously-covered line in 1 file lost coverage.
Coverage Stats
💛 - Coveralls |
71e95c2 to
a226f47
Compare
59b3ac4 to
aa8a7e4
Compare
aa8a7e4 to
8256165
Compare
…to their defaults
…, matching the server
8256165 to
c094c3e
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
internal/reconcile/preference_test.go (1)
86-95: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winCover an omitted preference stored as empty.
Add a case with
current[name] == ""and an empty desired list. It should produce no reset because the server already resolves that value to the default.internal/reconcile/preference_reconciler_test.go (1)
108-137: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winCover empty stored values during export.
Add a preference with
Value: ""and a non-empty trait default, then assert it is omitted and the exported document round-trips without planned operations.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 870b9a80-10e5-4541-a4d5-40325a7ed505
📒 Files selected for processing (7)
cmd/reconcile.godocs/content/docs/reconcile.mdxdocs/content/docs/reference/cli.mdxinternal/reconcile/preference.gointernal/reconcile/preference_reconciler.gointernal/reconcile/preference_reconciler_test.gointernal/reconcile/preference_test.go
| var sets, resets []preferenceOp | ||
| for name, value := range desiredByName { | ||
| if value != serverValue(name) { | ||
| sets = append(sets, preferenceOp{action: opSet, name: name, value: value}) | ||
| } | ||
| } | ||
| for name, value := range current { | ||
| def, known := defaults[name] | ||
| if !known { | ||
| // A stored value whose trait no longer exists: leave it alone. The | ||
| // file cannot name it (unknown names fail), so nothing manages it. | ||
| continue | ||
| } | ||
| if _, listed := desiredByName[name]; listed { | ||
| continue | ||
| } | ||
| if value != def { | ||
| resets = append(resets, preferenceOp{action: opReset, name: name, value: def}) | ||
| } |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Normalize empty stored values consistently.
The planner recognizes "" as unset/default, but reset planning and export compare the raw value. This causes unnecessary resets and exports that do not round-trip cleanly.
internal/reconcile/preference.go#L71-L89: compareserverValue(name)with the default when deciding resets.internal/reconcile/preference_reconciler.go#L85-L92: omit empty stored values from export.internal/reconcile/preference_test.go#L86-L95: test that an omitted empty stored preference produces no operation.internal/reconcile/preference_reconciler_test.go#L108-L137: test that empty stored values are omitted and round-trip without changes.
📍 Affects 4 files
internal/reconcile/preference.go#L71-L89(this comment)internal/reconcile/preference_reconciler.go#L85-L92internal/reconcile/preference_test.go#L86-L95internal/reconcile/preference_reconciler_test.go#L108-L137
Stacked on #1737; will rebase onto main once #1731 and #1737 squash-merge.
What
A
Preferencekind forfrontier reconcileandfrontier export, for platform settingslike
disable_orgs_on_createand the invite mail template.How it behaves (per the RFC's rules)
desired state. A preference you list is set to your value; a preference you leave out is
written back to its trait default. This is the first kind to use reset-to-default.
its default is what removal means here.
default, sorted by name, so reconciling an export plans no changes.
Values are strings end to end, so a yes/no setting compares as
"true"or"false".Unknown names and duplicate names fail the plan. A stored value whose trait no longer
exists is left alone — the file cannot name it, so nothing manages it.
API use
ListPreferences(AdminService) reads the stored platform preferences.DescribePreferences(FrontierService) gives the valid platform traits and theirdefaults — both the source of defaults and the set of valid names.
CreatePreferences(AdminService) upserts a value; a reset writes the default back.Values are read from the DB on every call, so a write reaches all pods. There is a
standing TODO in
core/preference/service.goto cache platform preferences; if that landsas a boot-lifetime map, pods would serve stale values after a write. It needs a TTL or
read-through. Flagging it here so the cache is not added without that.
Tests
resets, unknown trait, duplicate name, empty name, and a stored value whose trait is
gone.
applying, export returns only overrides and round-trips, and an all-default export is
empty.